from present import FactSpec

from knowledge import Fact
from knowledge import Location
from knowledge import Person
from knowledge import Event
from knowledge import Group
from knowledge import Object
from knowledge import Date

import manage

import random

def debug(*strings):
   return
   for s in strings:
     print s,
   print

def choose(state, behavior):
   if type(behavior) == manage.Query:
      fact = getFact(state, behavior)
      if not fact:
         raise ValueError("page without fact: " + str(state.currentPage))
      state.factsPresented.append(fact)
      behavior.fact = fact
      debug("DECIDE: Query:\n\tfact: ", behavior.fact.fact.name,\
            "\n\taspect: ", behavior.fact.aspect,\
            "\n\twhich: ", behavior.fact.which,\
            "\n\tstateUpdated: ",\
            state.factsPresented[-1] is behavior.fact)
      return

   if type(behavior) == manage.DeclareSingle:
      fact = getFact(state, behavior)
      if not fact:
         raise ValueError("page without fact: " + str(state.currentPage))
      state.factsPresented.append(fact)
      behavior.fact = fact
      debug("DECIDE: DeclSing:\n\tfact: ", behavior.fact.fact.name, \
            "\n\taspect: ", behavior.fact.aspect,\
            "\n\twhich: ", behavior.fact.which,\
            "\n\tstateUpdated: ",\
            state.factsPresented[-1] is behavior.fact)
      return

   if type(behavior) == manage.DeclareTriple:
      i = 0
      while i < 3:
         fact = getFact(state, behavior)
         if not fact:
            raise ValueError("page without fact: " + str(state.currentPage))
         state.factsPresented.append(fact)
         behavior.facts[i] = fact
         i += 1
      debug("DECIDE: DeclMult:\n\tfact1: ", behavior.facts[0].fact.name,\
            "\n\taspect: ", behavior.facts[0].aspect,\
            "\n\twhich: ", behavior.facts[0].which,\
            "\n\tfact2: ", behavior.facts[1].fact.name, \
            "\n\taspect: ", behavior.facts[1].aspect,\
            "\n\twhich: ", behavior.facts[1].which,\
            "\n\tfact3: ", behavior.facts[2].fact.name,\
            "\n\taspect: ", behavior.facts[2].aspect,\
            "\n\twhich: ", behavior.facts[2].which,\
            "\n\tstateUpdated: ",\
            behavior.facts[0] is state.factsPresented[-3] and\
            behavior.facts[1] is state.factsPresented[-2] and\
            behavior.facts[2] is state.factsPresented[-1])
      return

   if type(behavior) == manage.Transition:
      behavior.newFact = None
      getTransition(state, behavior)
      if not behavior.newFact:
         debug("DECIDER:\n\tno good trans fact")
         raise ValueError("could not find transitionable fact")
      state.newPage = behavior.newFact.fact.page
      debug("DECIDE: Transition: \n\tfromFact: ",\
            behavior.fromFact.fact.name,\
            "\n\taspect: ", behavior.fromFact.aspect,\
            "\n\twhich: ", behavior.fromFact.which,\
            "\n\tcommon: ", behavior.commonality,\
            "\n\tnewFact: ", behavior.newFact.fact.name,\
            "\n\taspect: ", behavior.newFact.aspect,\
            "\n\twhich: ", behavior.newFact.which,\
            "\n\tstateUpdated: ",\
            state.factsPresented[-1] is behavior.newFact,\
            "\n\tstate.newPage: ", state.newPage)
      return

   raise TypeError('could not determine behavior type')
   return

def getFact(state, behavior):
   page = state.currentPage
   presentedFacts = state.factsPresented
   factList = page.facts
   #debug("factList:", factList)
   if not factList:
     behavior.transition = "transition"
     return None
   spec = None
   attempts = 0
   while attempts < 100:
     attempt = random.choice(factList)
     try:
       spec = makeFactSpec(attempt)
       if not isIn(spec, presentedFacts):
         return spec
     except TypeError:
       debug("\tBad fact type:", repr(attempt))
     except ValueError:
       debug("\tEmpty fact:", attempt.name, " attempts: ", attempts)
     attempts = attempts + 1
   behavior.transition = "transition"
   return None

def isIn(spec, list):
   for fs in list:
      debug("FACT[", spec.fact.name.lower().strip(),",",\
            fs.fact.name.lower().strip(),"]\n\tWHICH[",spec.which,\
            ",",fs.which,"]\n\tASPECT[",str(fs.aspect).strip(),\
            ",",str(spec.aspect).strip(),"]")
      if spec.fact.name.lower().strip() == fs.fact.name.lower().strip():
         if fs.which == spec.which:
            debug("\tTRUE")
            return True
         if (fs.aspect in ["birth", "death"] and\
               spec.aspect in ["birth", "death"]):
            debug("\tTRUE")
            return True
         if (fs.aspect in ["start", "end", "participants"]) and\
               (spec.aspect in ["start", "end", "participants"]):
            debug("\tTRUE")
            return True
      if spec.fact == fs.which or spec.which == fs.fact:
         debug("\tTRUE")
         return True
   debug("\tFALSE")
   return False

def makeFactSpec(fact):
   typ = type(fact)
   fields = []
   if (typ == Location):
      fields = ["events", "contains", "within"]
   elif (typ == Person):
      fields = ["birth", "death", "caused", "participated"]
   elif (typ == Event):
      fields = ["start", "end", "location", "causes", "instigators",\
            "participants"]
      # Reduces issues:
      #fields = ["start", "end", "location", "causes"]
   elif (typ == Group):
      fields = ["members"]
   elif (typ == Object):
      fields = ["creation", "creator", "location"]
   else:
      raise TypeError("could not determine fact type (raw type is "\
            + str(typ) + ")")
   choice = random.choice(fields)
   attr = getattr(fact, choice)
   while not attr:
      fields.remove(choice)
      if len(fields) == 0:
         raise ValueError("empty fact: " + str(fact))
      choice = random.choice(fields)
      attr = getattr(fact, choice)
   if type(attr) in (list, set, tuple):
      return FactSpec(fact, choice, random.choice(list(attr)))
   else:
      return FactSpec(fact, choice, attr)

def getTransition(state, behavior):
   fromFact = state.factsPresented[-1]
   aspect = "none"
   choice = random.randint(1,3)
   mustTime = False
   mustLoca = False
   while not mustTime or not mustLoca:
      if not mustTime and (mustLoca or choice == 1):
         if fromFact.aspect in ("contains", "within", "location"):
            aspect = "location r"
            break
         else:
            aspect = "location"
            try:
               fromFact = getLocationSpec(fromFact.fact)
               break
            except TypeError:
               mustTime = True
            except ValueError:
               mustTime = True
      else:
         if fromFact.aspect in ("start", "end"):
            aspect = "time r"
            break
         else:
            aspect = "time"
            try:
               fromFact = getTimeSpec(fromFact.fact)
               break
            except TypeError:
               mustLoca = True
            except ValueError:
               mustLoca = True
   if (mustTime and mustLoca):
      debug ("DECIDER: getTransition\n\tno good transitionable fact")
      return 
   tries = 1
   newFact = None
   for fact in state.factList:
      if fact.page in state.pagesVisited:
         continue
      if type(fact) == Event and (aspect == "time" or aspect == "time r"):
         date_or_event = fromFact.which
         #debug("FROM:\t", fromFact)
         #debug("ASPECT:\t", aspect)
         #debug("DATE OR EVENT:\t", date_or_event)
         #debug("FACT:\t", fact,"\n\tbegin:",fact.start,"\n\tend:",fact.end)
         if isinstance(date_or_event, Event):
           if date_or_event.start or date_or_event.end:
             date = date_or_event.start or date_or_event.end
           else:
             continue
         else:
           date = date_or_event
         if fact.start and fact.end and date.within(fact.start, fact.end):
            try:
               timeFact = getTimeSpec(fact)
            except TypeError:
               return
            except ValueError:
               return
            if isIn(timeFact, state.factsPresented):
               debug("\tCONTINUING")
               continue
            debug("\tBREAKING")
            newFact = timeFact
            newFact = timeFact
            break
      if aspect == "location" or aspect == "location r":
         location = fromFact.which.name.lower
         try:
            locSpec = getLocationSpec(fact)
            if isIn(locSpec, state.factsPresented):
               debug("\tCONTINUING")
               continue
         except TypeError:
            return
         except ValueError:
            return
         if locSpec and location == locSpec.which.name.lower:
            newFact = locSpec
            debug("\tBREAKING")
            break
   if newFact:
      behavior.fromFact = fromFact
      behavior.commonality = aspect
      behavior.newFact = newFact
      state.factsPresented.append(newFact)
   debug("DECIDER: getTransition\n\tfromFact: ", behavior.fromFact, \
         "\n\tcommonality: " , behavior.commonality, \
         "\n\tnewFact:", behavior.newFact)
   return 

def getLocationSpec(fact):
   typ = type(fact)
   fields = []
   if (typ == Event):
      fields = ["location"]
   elif (typ == Object):
      fields = ["location"]
   else:
      raise TypeError("no location")
   choice = random.choice(fields)
   attr = getattr(fact, choice)
   while not attr:
      fields.remove(choice)
      if len(fields) == 0:
         raise ValueError("empty fact: " + str(fact))
      choice = random.choice(fields)
      attr = getattr(fact, choice)
   if type(attr) in (list, set, tuple):
      return FactSpec(fact, choice, random.choice(list(attr)))
   else:
      return FactSpec(fact, choice, attr)

def getTimeSpec(fact):
   typ = type(fact)
   fields = []
   if (typ == Person):
      fields = ["birth"]
   elif (typ == Event):
      fields = ["start"]
   elif (typ == Object):
      fields = ["creation"]
   else:
      raise TypeError("no time")
   choice = random.choice(fields)
   attr = getattr(fact, choice)
   while not attr:
      fields.remove(choice)
      if len(fields) == 0:
         raise ValueError("empty fact: " + str(fact))
      choice = random.choice(fields)
      attr = getattr(fact, choice)
   if type(attr) in (list, set, tuple):
      return FactSpec(fact, choice, random.choice(list(attr)))
   else:
      return FactSpec(fact, choice, attr)


def isEmptyFact(fact):
   typ = type(fact)
   fields = []
   if (typ == Location):
      fields = ["events", "contains", "within"]
   elif (typ == Person):
      fields = ["birth", "death", "caused", "participated"]
   elif (typ == Event):
      fields = ["start", "end", "location", "causes", "instigators",\
            "participants"]
   elif (typ == Group):
      fields = ["members"]
   elif (typ == Object):
      fields = ["creation", "creator", "location"]
   else:
      return True
   for choice in fields:
      attr = getattr(fact, choice)
      if attr != None:
         if type(attr) in (list, set, tuple) and len(attr) == 0:
            continue
         return False
   return True 


